﻿using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Text;
using XcoAppSpaces.Core;
using Microsoft.Ccr.Core;
using System.Threading;
using NUnit.Framework;
using XcoAppSpaces.Contracts.Serialization;
using XcoAppSpaces.Serialization.Binary;
using XcoAppSpaces.Serialization.Json;
using XcoAppSpaces.Contracts.Communication;

namespace test.XcoAppSpaces.Core
{
	[TestFixture]
	public class testPublisherPerformance
	{
		private const int msgCount = 10000;
		private const int maxTimeSeconds = 15;

		class PublisherWorker : PortSet<Subscribe<int>, Unsubscribe<int>>
		{
			public XcoPublisher<int> Publisher = new XcoPublisher<int>();
		}

		[Test]
		public void TestPerformance_XcoPublisher()
		{
			using (XcoAppSpace s1 = new XcoAppSpace("tcp.port=8001"),
				s2 = new XcoAppSpace("tcp.port=8002"))
			{
				var worker = new PublisherWorker();
				s2.RunWorker(worker);

				var proxy = s1.ConnectWorker<PublisherWorker>("localhost:8002");

				var sw = new Stopwatch();
				int received = 0;
				var evt = new ManualResetEvent(false);
				var subscriptionPort = s1.Receive<int>(i =>
				{
					Interlocked.Increment(ref received);
					if (received == msgCount)
					{
						sw.Stop();
						evt.Set();
					}
				});

				proxy.Post(new Subscribe<int>(subscriptionPort));
				Thread.Sleep(100);

				sw.Start();
				for (int i = 0; i < msgCount; i++)
				{
					worker.Publisher.Publish(i);
				}

				evt.WaitOne();

				Console.WriteLine("XcoPublisher Performance: " + (int)((double)msgCount / (sw.ElapsedMilliseconds / 1000.0)) + " Messages/s");
			}
		}

		//[Test]
		//public void TestPerformance_Send()
		//{
		//    using (XcoAppSpace s1 = new XcoAppSpace("tcp.port=8001"),
		//        s2 = new XcoAppSpace("tcp.port=8002"))
		//    {
		//        int received = 0;
		//        var evt = new ManualResetEvent(false);

		//        s2.Run<int>(i => 
		//        {
		//            Interlocked.Increment(ref received);
		//            if (received == msgCount)
		//                evt.Set();
		//        });
		//        var proxy = s1.Connect<int>("localhost:8002");

		//        var dpq = new DispatcherQueue();
		//        var senderPort = dpq.ReceiveSequentially<int>(i => proxy.Send(i));


		//        var sw = Stopwatch.StartNew();

		//        for (int i = 0; i < msgCount; i++)
		//        {
		//            senderPort.Post(i);
		//            //proxy.Send(i);
		//        }

		//        evt.WaitOne();
		//        sw.Stop();

		//        Console.WriteLine("Time: " + sw.ElapsedMilliseconds + " ms");
		//    }
		//}

		//[Test]
		//public void TestPerformance_PostWithXcoExclusive()
		//{
		//    using (XcoAppSpace s1 = new XcoAppSpace("tcp.port=8001"),
		//        s2 = new XcoAppSpace("tcp.port=8002"))
		//    {
		//        int received = 0;
		//        var evt = new ManualResetEvent(false);

		//        s2.Run<int>(i =>
		//        {
		//            Interlocked.Increment(ref received);
		//            if (received == msgCount)
		//                evt.Set();
		//        });
		//        var proxy = s1.Connect<int>("localhost:8002");

		//        var posterWorker = new SequentialPosterWorker { receiver = proxy };
		//        s1.RunWorker(posterWorker);


		//        var sw = Stopwatch.StartNew();

		//        for (int i = 0; i < msgCount; i++)
		//        {
		//            posterWorker.Post(i);
		//            //proxy.Send(i);
		//        }

		//        evt.WaitOne();
		//        sw.Stop();

		//        Console.WriteLine("Time: " + sw.ElapsedMilliseconds + " ms");
		//    }
		//}

		//class SequentialPosterWorker : Port<int>
		//{
		//    public Port<int> receiver;

		//    Port<Exception> errorPort = new Port<Exception>();
		//    Port<Ack> ackPort = new Port<Ack>();

		//    [XcoExclusive]
		//    //IEnumerator<ITask> Process(int msg)
		//    void Process(int msg)
		//    {
		//        //receiver.PostWithCausality(msg, errorPort, ackPort);
		//        //yield return Arbiter.Choice(errorPort.Receive(), ackPort.Receive());
				
		//        receiver.Send(msg);
		//    }
		//}
	}
}
